#include "Vector2D.h"

Vector2D::Vector2D():
x(0.f),
y(0.f) {

}

Vector2D::Vector2D(float x, float y) :
x(x),
y(y) {

}

Vector2D::~Vector2D() {

}

Vector2D Vector2D::GetVectorByPolarAngle(float angle) {
	// convert angle to rads
	float rads = angle * PI / HALF_CIRCLE_DEG;
	return Vector2D(cosf(rads), sinf(angle));
}

void Vector2D::Add(const Vector2D& v) {
	x += v.x;
	y += v.y;
	return;
}

void Vector2D::Add(float x, float y) {
	this->x += x;
	this->y += y;
}

void Vector2D::Substract(const Vector2D& v) {
	x -= v.x;
	y -= v.y;
	return;
}

void Vector2D::Scale(float scl) {
	x *= scl;
	y *= scl;
	return;
}

float Vector2D::Dot(const Vector2D& v) const {
	return x * v.x + y * v.y;
}

void Vector2D::MoveBy(const Vector2D& offset) {
	Add(offset);
	return;
}

void Vector2D::MoveBy(float xOffset, float yOffset) {
	Add(xOffset, yOffset);
	return;
}

float Vector2D::GetPolarAngle() const {
	float angle;

	if (FloatEquals(x, 0.f)) {
		// would divide by 0
		if (FloatEquals(y, 0.f)) {
			// null vector
			angle = 0.f;
		} else {
			// vertical vector
			// by default, set this to a quarter of a circle, make adjustments later
			angle = PI / 2.f;
		}
	} else {
		if (FloatEquals(y, 0.f)) {
			// horizontal vector
			// by default, set this to a 0 angle, make adjustments later
			angle = 0.f;
		} else {
			// vector with non null x and y
			// get the angle in rads with the arc tangeant
			angle = atanf( ((y < 0.f) ? -y : y) / ((x < 0.f) ? -x : x) );
		}
	}

	// absolute angle
	angle = fabs(angle);
	// convert angle to degrees, between 0 and 90
	angle *= HALF_CIRCLE_DEG / PI;

	// make adjustments based on quadrant
	if (x >= 0.f) {
		if (y >= 0.f) {
			// top right
			return angle;
		} else {
			// bottom right
			return FULL_CIRCLE_DEG - angle;
		}
	} else {
		if (y >= 0.f) {
			// top left
			return HALF_CIRCLE_DEG - angle;
		} else {
			// bottom left
			return HALF_CIRCLE_DEG + angle;
		}
	}
}

float Vector2D::GetAngleBetween(const Vector2D& v) const {
	float len1 = Length();
	float len2 = v.Length();
	float angle;

	if (FloatEquals(len1, 0.f) || FloatEquals(len2, 0.f)) {
		// would divide by 0
		// default angle would be 0
		angle = 0.f;
	} else {
		// angle between the two vectors
		angle = acosf(Dot(v) / (len1 * len2));
		// absolute angle
		angle = fabs(angle);
		// convert angle to rads
		angle *= HALF_CIRCLE_DEG / PI;
	}

	// make sure the angle is the shortest between the two vectors
	if (angle > HALF_CIRCLE_DEG / 2.f) {
		angle = HALF_CIRCLE_DEG - angle;
	}

	return angle;
}

float Vector2D::Length() const {
	return sqrtf(LengthSq());
}

float Vector2D::LengthSq() const {
	return x * x + y * y;
}

void Vector2D::Normalize() {
	if (!FloatEquals(x, 0.f) || !FloatEquals(y, 0.f)) {
		// if the vector is not null
		float len = Length();
		Scale(1.f / len);
	}

	// otherwise do not bother calculating the length
	return;
}

void Vector2D::Display() const {
	// display the vector in the console in teh (x, y) format
	std::cout << "(" << x << ", " << y << ")";
	return;
}

bool Vector2D::operator==(const Vector2D& v) const {
	// differences in coordinates
	float dx = x - v.x;
	float dy = y - v.y;

	// check if they are equal
	return FloatEquals(dx, 0.f) && FloatEquals(dy, 0.f);
}

Vector2D Vector2D::operator*(float scale) const {
	Vector2D r = Vector2D(*this);
	r.Scale(scale);
	return r;
}

Vector2D Vector2D::operator/(float scale) const {
	Vector2D r = Vector2D(*this);
	r.Scale(1.f / scale);
	return r;
}

float Vector2D::operator*(const Vector2D& v) const {
	return Dot(v);
}

Vector2D Vector2D::operator+(const Vector2D& v) const {
	Vector2D r = Vector2D(*this);
	r.Add(v);
	return r;
}

Vector2D Vector2D::operator-(const Vector2D& v) const {
	Vector2D r = Vector2D(*this);
	r.Substract(v);
	return r;
}

void Vector2D::operator*=(float scale) {
	Scale(scale);
	return;
}

void Vector2D::operator/=(float scale) {
	Scale(1.f / scale);
	return;
}

void Vector2D::operator+=(const Vector2D& v) {
	Add(v);
	return;
}

void Vector2D::operator-=(const Vector2D& v) {
	Substract(v);
	return;
}
